이 노트북은 제이크 반더플라스(Jake VanderPlas)의 A Whirlwind Tour of Python(OReilly Media, 2016)를 기반으로 만들어졌습니다. 이 내용은 CC0 라이센스를 따릅니다. 전체 노트북의 목록은 https://github.com/rickiepark/WhirlwindTourOfPython 에서 볼 수 있습니다.

< 함수 | 목차 | 반복자 >

에러와 예외처리

프로그래머로서의 기술에 상관없이 코딩 실수는 하기 마련입니다. 여기에는 세 종류의 실수가 있습니다:

여기에서는 어떻게 실행시 에러를 깔끔하게 다루는지 배웁니다. 파이썬은 예외처리 핸들링 프레임워크로 실행시 에러를 처리합니다.

실행 에러

파이썬 코딩을 해보았다면 실행 에러를 만난 적이 있을 것입니다. 이 에러는 다양한 곳에서 일어 납니다.

예를 들어, 정의되어 있지 않은 변수를 참조할 때 발생합니다:

또는 정의되지 않은 연산을 시도할 때입니다:

또는 수학적으로 계산할 수 없는 연산을 시도할 때입니다:

또는 존재하지 않는 원소에 접근할 때입니다:

각 경우에 파이썬은 단순히 에러가 일어난 것을 알려주는 것 뿐만 아니라 정확히 무엇이 잘못 되었는지 에러가 발생한 코드의 위치는 어디인지의 정보를 포함한 의미있는 예외를 발생시킵니다. 이런 에러의 의미를 사용하면 코드에 있는 문제를 찾아가는데 매우 도움이 됩니다.

예외 처리: tryexcept

실행시 예외를 다루기 위한 도구는 try...except 절입니다. 기본 구조는 다음과 같습니다:

첫 번째 블럭에서 에러가 발생하지 않았기 때문에 두 번째 블럭은 실행되지 않습니다. try 블럭안에 잘못된 코드를 넣으면 어떻게 되는지 보겠습니다:

try 문 안에서 에러가 발생하면(여기서는 ZeroDivisionError) 캐치되어 except 문이 실행됩니다.

함수나 코드에서 사용자의 입력을 체크하는데 자주 사용하는 방법입니다. 예를 들어 0으로 나누는 에러를 캐치하여 $10^{100}$와 같이 아주 충분히 큰 값을 반환하는 함수를 만들 수 있습니다:

이 함수에는 교묘한 문제가 있습니다. 다른 종류의 예외가 발생하면 어떻게 될까요? 가령, 다음은 예상하지 못한 상황입니다:

정수와 문자열을 사용해 나눗셈을 하면 TypeError가 발생됩니다. 이 에러도 과도하게 캐치하여 ZeroDivisionError로 간주하는 셈이 됩니다! 이런 이유 때문에 명시적으로 캐치할 예외를 지정하는 것이 좋습니다:

이제 0으로 나누는 에러만 캐치하고 나머지 에러는 그냥 통과시킵니다.

예외 발생: raise

파이썬을 사용할 때 예외에 담긴 정보가 얼마나 유용한지 보았습니다. 여러분이 작성한 코드에서도 유용한 예외는 동일한 가치가 있습니다. 이렇게 하면 코드를 사용할 사용자(무엇보다도 자기자신!)가 에러가 발생된 원인을 쉽게 찾을 수 있습니다.

자기자신의 예외를 발생시키는 방법은 raise 문을 사용하는 것입니다. 예를 들어:

이에 대한 유용한 예를 위해서 앞서 정의한 fibonacci 함수로 돌아가 보죠:

def fibonacci(N):
    L = []
    a, b = 0, 1
    while len(L) < N:
        a, b = b, a + b
        L.append(a)
    return L

이 함수에서 한 가지 문제점은 입력값이 음수일 수 있다는 것입니다. 음수가 입력되어도 이 함수에서 어떤 에러도 발생시키지는 않습니다. 하지만 음수 N을 지원하지 않는다는 점을 사용자에게 알리고 싶습니다. 관례적으로 잘못된 파라미터 값에의해 발생한 에러는 ValueError를 발생시킵니다:

이제 사용자는 왜 입력이 잘못되었는지 정확히 알게됩니다. 심지어 try...except 블럭을 사용하여 이를 캐치할 수 있습니다!

예외에 대해 자세히 알아보기

간단히 앞으로 볼 수 있는 다른 개념에 대해 언급하겠습니다. 너무 자세한 개념이나 왜, 어떻게 사용하는지 설명하지 않겠습니다. 대신 간단한 사용법을 보이고 나중에 스스로 더 찾아보도록 돕겠습니다.

에러 메세지 참조

try...except 문에서 이따금 에러 메세지 자체를 다루어야할 때가 있습니다. 이럴 때는 as 키워드를 사용합니다:

이 패턴을 사용해 함수의 예외 처리를 다양하게 커스터마이징할 수 있습니다.

독자적인 예외 정의하기

기본 예외말고도 클래스 상속을 통해 독자적인 예외를 정의할 수 있습니다. 예를 들어 특별한 종류의 ValueError가 필요하면 다음과 같이 씁니다:

이 에러만 캐치하는 try...except 블럭을 사용할 수 있습니다:

커스터마이징이 많이 필요한 코드일수록 이 용법이 유용합니다.

try...except...else...finally

tryexcept 외에 elsefinally 키워드를 사용해 예외 처리를 정교하게 튜닝할 수 있습니다. 기본적인 구조는 다음과 같습니다:

else의 용도는 명확하지만 finally는 왜 필요할까요? 글쎄요, finally 절은 실제로 에러가 있던 없던 실행됩니다. 보통 어떤 작업이 완료되고 나서 자원을 정리하는 경우에 사용되곤 합니다.

< 함수 | 목차 | 반복자 >